home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 19 / Mac Magazin and MacEasy Magazine CD - Issue 19.iso / Musik & Kunst / Ear Workout 2.1 / source code / ear_intervals.cp < prev    next >
Text File  |  1996-01-06  |  17KB  |  533 lines

  1.  
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <math.h>
  6.  
  7. #include <OSUtils.h>
  8. #include <QuickDraw.h>
  9. #include <Sound.h>
  10.  
  11. #define NEED_MAC_STUFF 1
  12.  
  13. #include "Ninkasi:C++ util:generic.h"
  14. #include "Ninkasi:C++ util:complete_window.h"
  15. #include "ear_defines.h"
  16. #include "ear_decl.h"
  17. #include "ear_prototypes.h"
  18.  
  19. DEN_MOTHER_T interval_den_mother;
  20. void choose_interval(int *note1,int *note2,
  21.     int *duration1,int *duration2,int *rest_between,
  22.     int *abs_i,int *lower_note,int *higher_note,
  23.     int max_interval,int *interval_enabled,
  24.     int mean_note,double typical_tempo,int *shorter_duration);
  25.         
  26.         
  27.     void
  28. interval_den_mother(complete_window *my_complete_window)
  29.     {
  30.       //--- decoder string for controls:
  31.       static char **decoder_string;
  32.       static int have_decoder_string = 0;
  33.       //--- their score:
  34.       static int ntries = 0;
  35.       static int nright = 0;
  36.           static int nright_list[MAX_INTERVAL+1],nwrong_list[MAX_INTERVAL+1];
  37.       //--- keeping track of my current state:
  38.       static int first_time = 1;
  39.       static int they_have_interval_to_consider = 0;
  40.       static int melodic_or_harmonic = 1;
  41.       static int play_it,give_hint,type_of_hint,answer,they_did_something;
  42.       static int they_gave_answer,twiddle_radio_buttons,need_to_redraw,
  43.               twiddle_check_boxes,need_to_redraw_all,ready_to_update,
  44.               right,cleared_scores,changed_tempo;
  45.       static int current_icon = BLANK_ICON_ID; 
  46.       //--- parameters that determine what intervals I play and how I play them:
  47.       #define TYPICAL_TEMPO_MELODIC 105
  48.       #define TYPICAL_TEMPO_HARMONIC 45
  49.       static double typical_tempo = TYPICAL_TEMPO_MELODIC;
  50.       static int mean_note = 66;
  51.       static int interval_enabled[MAX_INTERVAL+1];
  52.       //--- about the current interval:
  53.       static int note1,note2,duration1,duration2,rest_between,abs_i,
  54.                shorter_duration;
  55.       static int lower_note = -999;
  56.       static int higher_note = -999;
  57.       
  58.       char nifty_name[100];
  59.       int nifty_index,recognized;
  60.       GrafPtr save_graf;
  61.  
  62.       they_did_something = 0;
  63.       give_hint = 0;
  64.       play_it = 0;
  65.       they_gave_answer = 0;
  66.       twiddle_radio_buttons = 0;
  67.       twiddle_check_boxes = 0;
  68.       need_to_redraw = 0;
  69.       need_to_redraw_all = 0;
  70.       ready_to_update = 0;
  71.       cleared_scores = 0;
  72.       changed_tempo = 0;
  73.       
  74.       if (first_time) {
  75.         first_time = 0;
  76.             for (int i=0; i<=MAX_INTERVAL; i++) {
  77.               nright_list[i] = 0;
  78.               nwrong_list[i] = 0;
  79.               interval_enabled[i] = (i!=0) && (i<=12);
  80.             }
  81.       }
  82.             
  83.       if (!have_decoder_string) {
  84.         decoder_string = (char **) GetString((short) INTERVAL_DLOG_ID);
  85.         if (!VALID_HANDLE(decoder_string))
  86.           bail_out("unable to get decoder string");
  87.         HLock((char **) decoder_string);
  88.         have_decoder_string = 1;
  89.       }
  90.       switch(my_complete_window->whassup) {
  91.         case complete_window_created:
  92.           need_to_redraw = 1;
  93.           need_to_redraw_all = 1;
  94.           break;
  95.         case complete_window_redraw:
  96.           need_to_redraw = 1;
  97.           need_to_redraw_all = 1;
  98.           ready_to_update = 1; //-- main program does begin update & sets graf port
  99.           break;
  100.         case complete_window_action:
  101.           part_number_to_nifty_label(nifty_name,&nifty_index,
  102.             *decoder_string,my_complete_window->part_number);
  103.           if (nifty_index != -999) {
  104.             recognized = 0;
  105.             if (strcmp(nifty_name,"answers")==0) {
  106.               recognized = 1;
  107.               they_gave_answer = 1;
  108.               need_to_redraw = 1;
  109.               answer = nifty_index;
  110.             }
  111.             if (strcmp(nifty_name,"enabled")==0) {
  112.               twiddle_check_boxes = 1;
  113.               need_to_redraw = 1;
  114.               if (nifty_index>=0 && nifty_index<=MAX_INTERVAL)
  115.                 interval_enabled[nifty_index] = !interval_enabled[nifty_index];
  116.               recognized = 1;
  117.             }
  118.             if (strcmp(nifty_name,"play_again")==0) {
  119.               recognized = 1;
  120.               play_it = 1;
  121.             }
  122.             if (strcmp(nifty_name,"fifth")==0) {
  123.               recognized = 1;
  124.               give_hint = 1;
  125.               type_of_hint = 6;
  126.             }
  127.             if (strcmp(nifty_name,"octave")==0) {
  128.               recognized = 1;
  129.               give_hint = 1;
  130.               type_of_hint = 1;
  131.             }
  132.             if (strcmp(nifty_name,"connecting_scale")==0) {
  133.               recognized = 1;
  134.               give_hint = 1;
  135.               type_of_hint = 2;
  136.             }
  137.             if (strcmp(nifty_name,"play_lower")==0) {
  138.               recognized = 1;
  139.               give_hint = 1;
  140.               type_of_hint = 3;
  141.             }
  142.             if (strcmp(nifty_name,"compare_with_another")==0) {
  143.               recognized = 1;
  144.               give_hint = 1;
  145.               type_of_hint = 4;
  146.             }
  147.             if (strcmp(nifty_name,"inv")==0) {
  148.               recognized = 1;
  149.               give_hint = 1;
  150.               type_of_hint = 5;
  151.             }
  152.             if (strcmp(nifty_name,"tempol")==0) {
  153.               int bump;
  154.               bump = typical_tempo*.05;
  155.               if (bump<1) bump = 1;
  156.               typical_tempo -= bump;
  157.               if (typical_tempo<10) typical_tempo=10;
  158.               changed_tempo = 1;
  159.               need_to_redraw = 1;
  160.             }
  161.             if (strcmp(nifty_name,"tempoh")==0) {
  162.               int bump;
  163.               bump = typical_tempo*.05;
  164.               if (bump<1) bump = 1;
  165.               typical_tempo += bump;
  166.               if (typical_tempo>300) typical_tempo=300;
  167.               changed_tempo = 1;
  168.               need_to_redraw = 1;
  169.             }
  170.             if (strcmp(nifty_name,"clear_scores")==0) {
  171.               recognized = 1;
  172.               ntries = 0;
  173.               nright = 0;
  174.               {
  175.                 int i;
  176.                 for (i=0; i<=MAX_INTERVAL; i++) {
  177.                   nright_list[i] = 0;
  178.                   nwrong_list[i] = 0;
  179.                 }
  180.               }
  181.               need_to_redraw = 1;
  182.               cleared_scores = 1;
  183.               current_icon = BLANK_ICON_ID;
  184.             }
  185.             if (strcmp(nifty_name,"melodic")==0) {
  186.               melodic_or_harmonic = 1;
  187.               twiddle_radio_buttons = 1;
  188.               need_to_redraw = 1;
  189.               typical_tempo = TYPICAL_TEMPO_MELODIC;
  190.               recognized = 1;
  191.             }
  192.             if (strcmp(nifty_name,"harmonic")==0) {
  193.               melodic_or_harmonic = 2;
  194.               twiddle_radio_buttons = 1;
  195.               need_to_redraw = 1;
  196.               typical_tempo = TYPICAL_TEMPO_HARMONIC;
  197.               recognized = 1;
  198.             }
  199.             they_did_something = recognized;
  200.           }//--end if they hit a valid control
  201.           break;
  202.         case complete_window_erase:
  203.           they_have_interval_to_consider = 0;
  204.           first_time = 1;
  205.           interval_window_exists = 0;
  206.           return;
  207.       }
  208.  
  209.  
  210.       if (they_gave_answer) {
  211.         right = (answer == abs_i);
  212.         ++ntries;
  213.         nright += right;
  214.         if (right) {
  215.           current_icon = CHECK_ICON_ID;
  216.           ++nright_list[abs_i];
  217.         }
  218.         else {
  219.           current_icon = X_ICON_ID;
  220.           ++nwrong_list[abs_i];
  221.         }
  222.         they_have_interval_to_consider = 0;
  223.       }
  224.       if (need_to_redraw) {
  225.         if (!ready_to_update) {
  226.           GetPort(&save_graf);
  227.           SetPort(my_complete_window->the_window);
  228.         }
  229.         if (twiddle_radio_buttons || need_to_redraw_all) {
  230.           set_ctl_by_nifty_label(my_complete_window->the_window,
  231.             "melodic",1,*decoder_string,(melodic_or_harmonic==1));
  232.           set_ctl_by_nifty_label(my_complete_window->the_window,
  233.             "harmonic",1,*decoder_string,(melodic_or_harmonic==2));
  234.         }
  235.         if (twiddle_check_boxes || need_to_redraw_all) {
  236.               for (int i=0; i<=MAX_INTERVAL; i++) {
  237.             set_ctl_by_nifty_label(my_complete_window->the_window,
  238.                      "enabled",i,*decoder_string,interval_enabled[i]);
  239.           }
  240.         }
  241.         if (need_to_redraw_all) {
  242.           refresh_text(my_complete_window,"tx",1,*decoder_string);
  243.         }
  244.         if (changed_tempo || twiddle_radio_buttons || need_to_redraw_all) {
  245.           Handle h;
  246.           char s[50];
  247.           get_item_by_nifty_label(my_complete_window->the_window,
  248.                   "tempo",1,*decoder_string,&h);
  249.           if (VALID_HANDLE(h)) {
  250.             sprintf(s+1,"%d",(int) typical_tempo);
  251.             s[0] = strlen(s+1);
  252.             SetIText(h,(unsigned char *) s);
  253.           }
  254.         }
  255.         if (they_gave_answer || cleared_scores || need_to_redraw_all) {
  256.           Handle h;
  257.           char s[50];
  258.           int i,tot;
  259.           get_item_by_nifty_label(my_complete_window->the_window,
  260.                   "total_score",1,*decoder_string,&h);
  261.           if (VALID_HANDLE(h)) {
  262.             if (ntries>0) {
  263.               sprintf(s+1,"%d %c",(int) ((100.*nright)/((double) ntries)),'%');
  264.               s[0] = strlen(s+1);
  265.             }
  266.             else {
  267.               sprintf(s+1,"           ");
  268.               s[0] = strlen(s+1);
  269.             }
  270.             TextSize((short) 18);
  271.             TextFont(geneva);
  272.             SetIText(h,(unsigned char *) s);
  273.             normal_text_style();
  274.           }
  275.           get_item_by_nifty_label(my_complete_window->the_window,
  276.                   "totals",1,*decoder_string,&h);
  277.           if (VALID_HANDLE(h)) {
  278.             if (ntries>0) {
  279.               sprintf(s+1,"%d / %d",(int) nright,(int) ntries);
  280.               s[0] = strlen(s+1);
  281.             }
  282.             else {
  283.               sprintf(s+1,"           ");
  284.               s[0] = strlen(s+1);
  285.             }
  286.             TextFont(geneva);
  287.             SetIText(h,(unsigned char *) s);
  288.             normal_text_style();
  289.           }
  290.           
  291.           TextFont((short) geneva);
  292.           for (i=0; i<=MAX_INTERVAL; i++) {
  293.             tot = nright_list[i]+nwrong_list[i];
  294.             if (need_to_redraw_all || cleared_scores
  295.                     || (they_gave_answer && i==abs_i)) {
  296.               get_item_by_nifty_label(my_complete_window->the_window,
  297.                   "scores",i,*decoder_string,&h);
  298.               if (VALID_HANDLE(h)) {
  299.                 if (tot>0) {
  300.                   sprintf(s+1,"%d / %d",(int) nright_list[i],(int) tot);
  301.                   s[0] = strlen(s+1);
  302.                 }
  303.                 else {
  304.                   sprintf(s+1,"          ");
  305.                   s[0] = strlen(s+1);
  306.                 }
  307.                 SetIText(h,(unsigned char *) s);
  308.               }
  309.             }
  310.           }//-- end loop over intervals
  311.           normal_text_style();
  312.         }
  313.         if (they_gave_answer) {
  314.           int i;
  315.           if (!right) {
  316.                 for (i=0; i<=MAX_INTERVAL; i++) {
  317.               if (i!=abs_i)
  318.                 hide_ctl_by_nifty_label(my_complete_window->the_window,
  319.                      "answers",i,*decoder_string);
  320.             }
  321.           }
  322.         }
  323.         if (they_gave_answer || cleared_scores || need_to_redraw_all) {
  324.           Handle hh;
  325.           Rect rr;
  326.           hh = GetIcon((short) current_icon);
  327.           if (VALID_HANDLE(hh)) {
  328.             get_rect_by_nifty_label(my_complete_window->the_window,
  329.                      "icon",1,*decoder_string, &rr);
  330.             PlotIcon(&rr,hh);
  331.           }
  332.             }
  333.         if (they_gave_answer && !right) {
  334.           int i;
  335.           rest((int)( 2. * 2000.*60./typical_tempo));
  336.               for (i=0; i<=MAX_INTERVAL; i++) {
  337.             if (i!=abs_i)
  338.               show_ctl_by_nifty_label(my_complete_window->the_window,
  339.                      "answers",i,*decoder_string);
  340.           }
  341.         }
  342.         if (!ready_to_update) {
  343.           SetPort(save_graf);
  344.         }
  345.       }//---end if need to redraw
  346.       if (!they_have_interval_to_consider) {
  347.         int previous_lower,previous_higher;
  348.         previous_lower = lower_note;
  349.         previous_higher = higher_note;
  350.         do {
  351.           choose_interval(¬e1,¬e2,&duration1,&duration2,&rest_between,
  352.             &abs_i,&lower_note,&higher_note,
  353.             MAX_INTERVAL,interval_enabled,
  354.             mean_note,typical_tempo,&shorter_duration);
  355.         } while (previous_lower==lower_note && previous_higher==higher_note);
  356.         play_it = 1;
  357.         they_have_interval_to_consider = 1;
  358.       }
  359.       if (play_it) {
  360.         int notes[4];
  361.         switch(melodic_or_harmonic) {
  362.           case 1: //-- melodic
  363.             notes[0] = note1;
  364.             play_chord(1,my_snd_chan,notes,duration1,1);
  365.             rest(rest_between);
  366.             notes[0] = note2;
  367.             play_chord(1,my_snd_chan,notes,duration2,1);
  368.             break;
  369.           case 2:
  370.             notes[0] = note1;
  371.             notes[1] = note2;
  372.             play_chord(2,my_snd_chan,notes,duration1,1);
  373.             break;
  374.         }
  375.       }
  376.       if (give_hint) {
  377.         int notes[4];
  378.         switch(type_of_hint) {
  379.           case 1: //-- play octave
  380.             notes[0] = lower_note;
  381.             play_chord(1,my_snd_chan,notes,shorter_duration,1);
  382.             notes[0] = lower_note+12;
  383.             play_chord(1,my_snd_chan,notes,shorter_duration,1);
  384.             break;
  385.           case 2: //-- play connecting scale
  386.             {
  387.               int *what_scale;
  388.               int i;
  389.               what_scale = interval_is_in_major_scale;
  390.               if (     !interval_is_in_major_scale[make_0_to_11(abs_i)]
  391.                   &&  interval_is_in_minor_scale[make_0_to_11(abs_i)])
  392.                 what_scale = interval_is_in_minor_scale;
  393.               for (i=0; i<=abs_i; i++) {
  394.                 if (what_scale[make_0_to_11(i)] || i==abs_i) {
  395.                   notes[0] = lower_note+i;
  396.                   play_chord(1,my_snd_chan,notes,shorter_duration/2,1);
  397.                 }
  398.               }
  399.             }
  400.             break;
  401.           case 3: //-- play the lower note
  402.             notes[0] = lower_note;
  403.             play_chord(1,my_snd_chan,notes,duration1,1);
  404.             break;
  405.           case 4: //-- compare with another interval
  406.           {
  407.             DialogPtr my_dialog;
  408.             short item_hit;
  409.             int interval;
  410.             my_dialog = GetNewDialog(SELECT_INTERVAL_MODAL_DLOG_ID,
  411.                 0,(WindowPtr) -1);
  412.             if (VALID_POINTER(my_dialog)) {
  413.               ModalDialog(0,&item_hit);
  414.               DisposDialog(my_dialog);
  415.               interval = item_hit - 1;
  416.               if (interval>=0 && interval<=MAX_INTERVAL) {
  417.                 notes[0] = lower_note;
  418.                 play_chord(1,my_snd_chan,notes,shorter_duration,1);
  419.                 notes[0] = lower_note+interval;
  420.                 play_chord(1,my_snd_chan,notes,shorter_duration,1);
  421.               }
  422.             }
  423.           }
  424.           break;
  425.           case 5: //-- play inversion
  426.             notes[0] = note1;
  427.             if (notes[0]==lower_note) notes[0]+=12;
  428.             play_chord(1,my_snd_chan,notes,duration1,1);
  429.             notes[0] = note2;
  430.             if (notes[0]==lower_note) notes[0]+=12;
  431.             play_chord(1,my_snd_chan,notes,duration1,1);
  432.             break;
  433.           case 6: //-- play fifth
  434.             notes[0] = lower_note;
  435.             play_chord(1,my_snd_chan,notes,shorter_duration,1);
  436.             notes[0] = lower_note+7;
  437.             play_chord(1,my_snd_chan,notes,shorter_duration,1);
  438.             break;
  439.         }
  440.       }
  441.  
  442.     }
  443.  
  444.  
  445.     void
  446. choose_interval(int *note1,int *note2,int *duration1,int *duration2,int *rest_between,
  447.         int *abs_i,int *lower_note,int *higher_note,
  448.         int max_interval,int *interval_enabled,
  449.         int mean_note,double typical_tempo,int *shorter_duration)
  450.     {
  451.         int interval,center,interval1,interval2,min_duration,
  452.             max_duration,temp;
  453.         double tempo,r1,r2,r3;
  454.             do {
  455.               interval1 = random_double()*max_interval*1.6;
  456.               interval2 = random_double()*max_interval*1.6;
  457.               if (interval1<interval2)
  458.                 interval=interval1;
  459.               else
  460.                 interval=interval2;
  461.               while (      random_double()<.5 
  462.                       && random_double()*max_interval*.3>interval)
  463.                 ++interval;
  464.             }while(interval<0 || interval>max_interval || !interval_enabled[interval]);
  465.             center = mean_note+(random_double()-.5)*8+(random_double()-.5)*8;
  466.                         /* mean_note plus or minus an something, biased towards
  467.                            pitches close to mean_note */
  468.             *abs_i = interval;
  469.             if (random_double()<.5) interval = -interval;
  470.             *note1 = center-interval/2;
  471.             *note2 = *note1 + interval;
  472.             
  473.         min_duration = .7 * 2000.*60./typical_tempo;
  474.         max_duration = 4 * 2000.*60./typical_tempo;
  475.     do {
  476.           tempo = typical_tempo*(1.+.2*(random_double()+random_double()-1.));
  477.           *duration1 = 2000.*60./tempo;
  478.           *duration2 = (*duration1)*small_integer_ratio();
  479.           if (random_double()<.5) {
  480.             temp = *duration1;
  481.             *duration1 = *duration2;
  482.             *duration2 = temp;
  483.           }
  484.           while (*duration1<min_duration || *duration2<min_duration) {
  485.             (*duration1) *= 2;
  486.             (*duration2) *= 2;
  487.           }
  488.           while (*duration1>max_duration || *duration2>max_duration) {
  489.             (*duration1) /= 2;
  490.             (*duration2) /= 2;
  491.           }
  492.         } while (*duration1>max_duration || *duration2>max_duration
  493.             || *duration1<min_duration || *duration2<min_duration);
  494.         *shorter_duration = (*duration1)/2;
  495.         while (*shorter_duration<min_duration) {
  496.           (*shorter_duration) *= 2;
  497.         }
  498.         while (*shorter_duration>min_duration*2) {
  499.           (*shorter_duration) /= 2;
  500.         }
  501.         r1 = random_double();
  502.         r2 = random_double();
  503.         r3 = random_double();
  504.         if (r1<.5) {
  505.           if (r2<.33)
  506.             *rest_between = *duration1;
  507.           else {
  508.             if (r2<.66)
  509.               *rest_between = *duration2;
  510.             else {
  511.               if (r3<.5)
  512.                 *rest_between = (*duration1) * small_integer_ratio();
  513.               else
  514.                 *rest_between = (*duration2) * small_integer_ratio();
  515.             }
  516.           }
  517.         }
  518.         else
  519.           *rest_between = 0;
  520.                           
  521.         ++ *rest_between; /* always make it slightly staccato */
  522.         -- *duration1; /* take the time out of the first note */
  523.         if (*note1<*note2) {
  524.           *lower_note = *note1;
  525.           *higher_note = *note2;
  526.         }
  527.         else {
  528.           *lower_note = *note2;
  529.           *higher_note = *note1;
  530.         }
  531.     }
  532.  
  533.